﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SerialAssistant
{
    public partial class FrmMain : Form
    {
        public FrmMain()
        {
            //master分支
            //master又新加了东西
            InitializeComponent();
        }

        /* 扫描本机可用的串口 */
        string[] portNames = SerialPort.GetPortNames();
        /* 波特率列表 */
        string[] bauds = { "9600", "38400", "57600", "115200" };
        /* 校验位列表 */
        string[] Parities = { "None", "Odd", "Even", "Mark", "Space" };
        /* 数据位列表 */
        string[] datas = { "5", "6", "7", "8" };
        /* 停止位列表 */
        string[] stops = { "None", "1", "2", "1.5" };

        //是否接收数据
        bool isReceive = true;
        //接收的字节数
        //int receiveCount = 0;
        //接收到的缓冲字节
        List<byte> reBuffers = new List<byte>();
        //发送的字节
        List<byte> sendBuffers = new List<byte>();
        //是否已经接收到数据帧头
        bool isFrameHead = false;
        //创建队列
        Queue<byte> frameQueue = new Queue<byte>();

        //public Action<byte[]> transmitData;

        public Testdele testdele;

        private void Form1_Load(object sender, EventArgs e)
        {
            #region 下拉参数初始化
            cmbPorts.Items.AddRange(portNames);
            cmbBauds.Items.AddRange(bauds);
            cmbParities.Items.AddRange(Parities);
            cmbDatas.Items.AddRange(datas);
            cmbStops.Items.AddRange(stops);

            /* 设置默认选择值 */
            cmbPorts.SelectedIndex = 0;
            cmbBauds.SelectedItem = "9600";
            cmbParities.SelectedItem = "None";
            cmbDatas.SelectedItem = "8";
            //注意：当数据位是6、7、8时 停止位只能是1或2，当数据位是5时 停止位只能是1或1.5
            cmbStops.SelectedItem = "1";
            #endregion

            //Form1 form1 = new Form1();
            //transmitData += form1.jieshou;
            //form1.sendData += run;
            //form1.Show();

            //Form1 form1 = new Form1();
            //testdele += new Testdele(form1.jieshou2);
            //form1.ShowDialog();
            //testdele?.Invoke(this, new TestHander() { MyData=1});
        }

        private void btnOpenPort_Click(object sender, EventArgs e)
        {
            if (!serialPort.IsOpen)
            {
                try
                {
                    serialPort.PortName = cmbPorts.SelectedItem.ToString();
                    serialPort.BaudRate = Convert.ToInt32(cmbBauds.SelectedItem);
                    serialPort.Parity = SwitchItem<Parity>(cmbParities.SelectedIndex);
                    serialPort.DataBits = Convert.ToInt32(cmbDatas.SelectedItem);
                    serialPort.StopBits = SwitchItem<StopBits>(cmbStops.SelectedIndex);
                    serialPort.Open();
                    btnOpenPort.Text = "关闭串口";
                    MessageBox.Show("串口" + cmbPorts.SelectedItem.ToString() + "成功打开！");
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "错误警告");
                }

            }
            else
            {
                serialPort.Close();
                btnOpenPort.Text = "打开串口";
                MessageBox.Show("串口" + cmbPorts.SelectedItem.ToString() + "已关闭！");
            }
        }

        T SwitchItem<T>(int index)
        {
            T result = default(T);
            Array arr = Enum.GetValues(typeof(T));
            for (int i = 0; i < arr.Length; i++)
            {
                if (i == index)
                {
                    result = (T)arr.GetValue(i);
                    break;
                }
            }
            return result;
        }

        //手动发送
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(rtSend.Text.Trim()) || !serialPort.IsOpen)
            {
                MessageBox.Show("发送的数据不能为空，或串口没有打开");
                return;
            }
            serialPort.Write(sendBuffers.ToArray(), 0, sendBuffers.Count);
            //更新发送字节数
            statusSendCount.Text = (Int32.Parse(statusSendCount.Text) + sendBuffers.Count).ToString();
        }

        //数据接收时触发
        private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (!isReceive)
            {
                //清空暂停期间的数据缓存
                serialPort.DiscardInBuffer();
                return;
            };

            byte[] buffers = new byte[serialPort.BytesToRead];
            serialPort.Read(buffers, 0, buffers.Length);
            reBuffers.AddRange(buffers);
            //更新接收字节数
            statusReceiveCount.Text = (Int32.Parse(statusReceiveCount.Text) + buffers.Length).ToString();

            //transmitData?.Invoke(buffers);

            string str = null;
            this.Invoke(new EventHandler(delegate
            {
                if (!startData_chb.Checked)
                {
                    if (!cbHEX1.Checked)
                    {
                        str = Encoding.GetEncoding("GB2312").GetString(buffers);
                        //这里因为在十六进制中 \0 会被当作结束符 不会显示，所以要转义
                        str = str.Replace("\0", "\\0");
                    }
                    else //十六进制接收
                    {
                        str = Transform.ToHexString(buffers, " ");
                    }
                    rtReceive.AppendText(str);
                    
                }
                else //解析数据
                {
                    
                    foreach (byte b in buffers)
                    {
                        frameQueue.Enqueue(b);
                    }
                    //如果没解析
                    if (!isFrameHead)
                    {
                        foreach (byte fb in frameQueue)
                        {
                            if (fb == 0x7f) //找到帧头
                            {
                                isFrameHead = true;
                                break;
                            }
                            else //不是帧头
                            {
                                frameQueue.Dequeue();
                                isFrameHead = false;
                            }
                        }
                    }

                    //如果解析过了
                    if(isFrameHead)
                    {
                        int dataLen = frameQueue.ToArray()[1];
                        if(frameQueue.Count >= 1 + 1 + dataLen + 2)
                        {
                            //校验
                            if (crc_chech(frameQueue))
                            {
                                //7f | 04 | 31 32 33 34 | DE 10
                                byte[] frameArr = frameQueue.ToArray();
                                dataFrame_txb.Text=Transform.ToHexString(frameArr);
                                data1_txb.Text = string.Format("{0:2x}", frameArr[2]);
                                data2_txb.Text = string.Format("{0:2x}", frameArr[3]);
                                data3_txb.Text = string.Format("{0:2x}", frameArr[4]);
                                data4_txb.Text = string.Format("{0:2x}", frameArr[5]);
                            }

                            foreach (var item in frameQueue)
                            {
                                frameQueue.Dequeue();
                            }
                            isFrameHead = false;
                        }
                    }
                }


            }));
        }

        
        //CRC校验
        private bool crc_chech(Queue<byte> bufferQueue)
        {
            //7f | 04 | 31 32 33 34 | DE 10
            byte[] temp = new byte[bufferQueue.Count - 2];
            Array.Copy(bufferQueue.ToArray(), 0, temp,0 , temp.Length);
            //返回校验码
            byte[] checkCodes = DataCheck.DataCrc16_Ccitt(temp, DataCheck.BigOrLittle.BigEndian);
            if (temp[temp.Length - 2] == checkCodes[0] && temp[temp.Length - 1] == checkCodes[1])
            {
                return true;
            }
            return false;
        }

        //暂停与启动 接收数据
        private void btnStop_Click(object sender, EventArgs e)
        {
            isReceive = !isReceive;
            btnStop.Text = isReceive ? "暂停" : "启动";
        }

        //以十六进制方式接收
        private void cbHEX1_CheckedChanged(object sender, EventArgs e)
        {
            string str = null;
            if (cbHEX1.Checked)
            {
                str = Transform.ToHexString(reBuffers.ToArray(), " ");
            }
            else
            {
                byte[] bytes = (byte[])reBuffers.ToArray();
                str = Encoding.GetEncoding("GB2312").GetString(bytes).Replace("\0", "\\0");
            }
            rtReceive.Text = str;
        }

        //手动清空
        private void btnClearReceive_Click(object sender, EventArgs e)
        {
            reBuffers.Clear();
            rtReceive.Clear();
            statusReceiveCount.Text = "0";
        }

        //自动清空按钮被点击时
        private void cbAutoClear_CheckedChanged(object sender, EventArgs e)
        {
            if ((sender as CheckBox).Checked)
            {
                timer.Start();
                return;
            }
            timer.Stop();
        }

        //定时器
        private void timer_Tick(object sender, EventArgs e)
        {
            if (Int32.Parse(statusReceiveCount.Text) >= 4096)
            {
                reBuffers.Clear();
                rtReceive.Clear();
                statusReceiveCount.Text = "0";
            }
        }

        //发送框失去焦点
        private void rtSend_Leave(object sender, EventArgs e)
        {
            string str = rtSend.Text;
            if (string.IsNullOrEmpty(str.Trim())) return;

            sendBuffers.Clear();
            if (cbHEX2.Checked)
            {
                //校验
                bool isHexString = Transform.IsHexString(str.Replace(" ", ""));
                if (isHexString)
                {
                    sendBuffers.AddRange(Transform.ToBytes(str.Replace(" ", "")));
                }
                else
                {
                    MessageBox.Show("请输入正确的十六进制数据！！");
                    //重新获取焦点
                    rtSend.Select();
                }
            }
            else
            {
                sendBuffers.AddRange(Encoding.GetEncoding("GB2312").GetBytes(str));
            }
        }

        //发送框的文本发生改变时
        private void rtSend_TextChanged(object sender, EventArgs e)
        {

        }

        //是否以十六进制发送
        private void cbHEX2_CheckedChanged(object sender, EventArgs e)
        {
            if (cbHEX2.Checked)
            {
                rtSend.Text = Transform.ToHexString(sendBuffers.ToArray(), 0, " ");
            }
            else
            {
                rtSend.Text = Encoding.GetEncoding("GB2312").GetString(sendBuffers.ToArray()).Replace("\0", "\\0");
            }
        }

        //清空发送的数据
        private void btnClearSend_Click(object sender, EventArgs e)
        {
            sendBuffers.Clear();
            statusSendCount.Text = "0";
            rtSend.Clear();
        }


    }
}
